﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the member entity.
    /// </summary>
    /// <remarks><pre>
    /// The entity regarding the disclosure level.
    /// 
    /// + Entire
    ///  + Extended
    ///   + Base
    ///    | - Rank(of the Base level)
    ///    | - AvatarFile(of the Base level)
    ///    | - Signature
    ///    | - TopicCount
    ///    | - PostCount
    ///    | - Flags
    ///    | - UpdatedOn
    ///    | - CreatedOn
    ///    + Keys
    ///     | - Account(of the same level)
    ///     + Primary
    ///      | - EntityID
    /// 
    /// Note: upper level includes lower level.
    /// </pre></remarks>
    public class ForumMemberEntity : AccountProfileEntity
    {
        #region Fields

        private ForumRankEntity _rank;
        private FileEntity _avatarFile;
        private ICollection<ForumPostEntity> _posts;
        private ICollection<ForumTopicEntity> _topics;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public ForumMemberEntity()
        {
            _rank = null;
            _avatarFile = null;
            _posts = new List<ForumPostEntity>();
            _topics = new List<ForumTopicEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the rank identifier.
        /// </summary>
        public virtual int RankID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the rank.
        /// </summary>
        public virtual ForumRankEntity Rank
        {
            get
            {
                return RankID != 0 ? _rank : null;
            }
            set
            {
                _rank = value;
                RankID = value != null ? value.EntityID : 0;
            }
        }

        /// <summary>
        /// Gets or sets the avatar file identifier.
        /// </summary>
        public virtual int AvatarFileID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the avatar file.
        /// </summary>
        public virtual FileEntity AvatarFile
        {
            get
            {
                return AvatarFileID == 0 ? null : _avatarFile;
            }
            set
            {
                _avatarFile = value;
                AvatarFileID = value == null ? 0 : value.EntityID;
            }
        }

        /// <summary>
        /// Gets or sets the signature.
        /// </summary>
        public virtual string Signature
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the topic count.
        /// </summary>
        public virtual int TopicCount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the post count.
        /// </summary>
        public virtual int PostCount
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the "karma" points.
        /// </summary>
        public virtual int KarmaPoints
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public virtual ForumMemberFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets or sets the topic collection.
        /// </summary>
        public virtual ICollection<ForumTopicEntity> Topics
        {
            get
            {
                return _topics;
            }
            set
            {
                _topics = value;
            }
        }

        /// <summary>
        /// Gets or sets the post collection.
        /// </summary>
        public virtual ICollection<ForumPostEntity> Posts
        {
            get
            {
                return _posts;
            }
            set
            {
                _posts = value;
            }
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Base)
            {
                obj["Rank"] = Rank != null
                    ? Rank.Disclose(DisclosureLevel.Base, options)
                    : null;
                obj["AvatarFile"] = AvatarFile != null
                    ? AvatarFile.Disclose(DisclosureLevel.Base, options)
                    : null;
                obj["Signature"] = Signature;
                obj["TopicCount"] = TopicCount;
                obj["PostCount"] = PostCount;
                obj["KarmaPoints"] = KarmaPoints;
                obj["Flags"] = Flags.ToString();
            }
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapping.
    /// </summary>
    public class ForumMemberMapping : EntityMapping<ForumMemberEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public ForumMemberMapping()
        {
            Table("fwk_ForumMembers");
            Id(x => x.EntityID, m =>
            {
                m.Column("MemberID");
                m.Generator(Generators.Identity);
            });
            ManyToOne(x => x.Account, m =>
            {
                m.Column("AccountID");
                m.ForeignKey("FK_fwk_ForumMembers_fwk_Accounts");
                m.Index("IX_fwk_ForumMembers");
                m.NotNullable(true);
                m.Fetch(FetchKind.Join);
            });
            Property(x => x.RankID, m =>
            {
                m.NotNullable(true);
            });
            ManyToOne(x => x.Rank, m =>
            {
                m.Column("RankID");
                m.NotFound(NotFoundMode.Ignore);
                m.Insert(false);
                m.Update(false);
            });
            Property(x => x.AvatarFileID, m =>
            {
                m.Column("AvatarFileID");
                m.NotNullable(true);
            });
            ManyToOne(x => x.AvatarFile, m =>
            {
                m.Column("AvatarFileID");
                m.NotFound(NotFoundMode.Ignore);
                m.Insert(false);
                m.Update(false);
            });
            Property(x => x.Signature, m =>
            {
                m.NotNullable(true);
                m.Length(1000);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(1000)");
                });
            });
            Property(x => x.TopicCount, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.PostCount, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.KarmaPoints, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.Flags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.Topics, m =>
            {
                m.Table("fwk_ForumTopics");
                m.Key(k =>
                {
                    k.Column("MemberID");
                    k.ForeignKey("FK_fwk_ForumTopics_fwk_ForumMembers");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Bag(x => x.Posts, m =>
            {
                m.Table("fwk_ForumPosts");
                m.Key(k =>
                {
                    k.Column("MemberID");
                    k.ForeignKey("FK_fwk_ForumPosts_fwk_ForumMembers");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.OneToMany();
            });
            Cache(m =>
            {
                m.Usage(CacheUsage.ReadWrite);
            });
        }
    }
}
